﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using Server.Data;
using Server.Core;


namespace Server.Net
{    
    /// <summary>
    /// Declaring event for managing connection problem
    /// </summary>
    /// <param name="sender">Default</param>
    /// <param name="player">Player</param>
    /// <param name="nickname">Nickname</param>
    public delegate void ClientSocketErrorHandler(object sender, Player player, String nickname);

    /// <summary>
    /// Declaring event for managing disconnect all players when server is stoping
    /// </summary>
    /// <param name="sender">Default</param>
    public delegate void DisconnectHandler(object sender);

    /// <summary>
    /// The net object
    /// </summary>
    public class ServerNet
    {
        /// <summary>
        /// Declaration of client socket error handler
        /// </summary>
        public event ClientSocketErrorHandler ClientSocketError;
        /// <summary>
        /// Declaration of disconnect handler
        /// </summary>
        public event DisconnectHandler Disconnect;

        private bool _isConnected;
        private TcpListener tcpListener;
        Thread threadListeningforConnections;

        /// <summary>
        /// Declaration tcp handler 
        /// </summary>
        public static ManualResetEvent tcpClientConnected = new ManualResetEvent(false);
        private ServerCore _serverCore;
        Int32 _port;
        
        /// <summary>
        /// Asociete event with a function
        /// </summary>
        /// <param name="player">Player</param>
        /// <param name="nickname">Nickname</param>
        protected virtual void OnClientSocketError(Player player, String nickname)
        {
            if (ClientSocketError!=null)
                ClientSocketError(this, player, nickname);
        }

        /// <summary>
        /// Asociete event with a function
        /// </summary>
        protected virtual void OnDisconnect()
        {
            if (Disconnect != null)
                Disconnect(this);
        }
       
        /// <summary>
        /// Create a new Server Net object that handles communication with clients
        /// </summary>
        /// <param name="port">Port use for listening</param>
        public ServerNet(Int32 port)
        {            
            _isConnected = false;
            _serverCore = new ServerCore(this);
            _port = port;
            
        }
        
        /// <summary>
        /// Restarts the server: send disconnect to all players, close connection and create a new instance
        /// </summary>
        public void RestartConnection()
        {
            DisconnectEvent();
            CloseConnection();
            _serverCore = null;
            _serverCore = new ServerCore(this);
            OpenConnection();
            
        }

        /// <summary>
        /// Opens a port for listening
        /// </summary>
        /// <returns>whether the operation was or not successful</returns>
        public bool OpenConnection()
        {
            try
            {
                if (!_isConnected)
                {
                    tcpListener = new TcpListener(IPAddress.Any, _port);
                    threadListeningforConnections = new Thread(new ThreadStart(StartListening));
                    threadListeningforConnections.Start();
                    _isConnected = true;
                    return true;
                }
                else return false;
            }
            catch (Exception)
            {
                _isConnected = false;
                return false;
            }
        }

        /// <summary>
        /// Close connection of the server and stop thread listesting.
        /// </summary>
        public void CloseConnection()
        {
            if (_isConnected)
            {
                _isConnected = false;
               // tcpClientConnected.Close();              
                threadListeningforConnections.Abort();
                tcpListener.Stop();
            }
        }

        /// <summary>
        /// Checks to see whether the object is listening the TCP port 
        /// </summary>
        /// <returns>true if the object listening, false otherwise</returns>
        public bool IsConnected()
        {
            return _isConnected;
        }

        /// <summary>
        /// Listens for new Tcp packets
        /// </summary>
        private void StartListening()
        {
        
            tcpListener.Start();
            while (true)
            {
                tcpListener.BeginAcceptSocket(new AsyncCallback(DoAcceptTcpClientCallback), tcpListener);
                tcpClientConnected.WaitOne();
                tcpClientConnected.Reset();

            }
           
        }

        /// <summary>
        /// Function that handles new tcp clients
        /// </summary>
        /// <param name="ar"></param>
        private void DoAcceptTcpClientCallback(IAsyncResult ar)
        {
            try
            {
                TcpListener listener = (TcpListener)ar.AsyncState;
                TcpClient client = listener.EndAcceptTcpClient(ar);
                Thread clientThread = new Thread(new ParameterizedThreadStart(this.HandleClientComm));
                clientThread.Start(client);
                tcpClientConnected.Set();
            }
            catch (Exception e)
            {
                //Console.WriteLine("DoAcceptTcpClientCallback exception: " + e.Message);
            }
        }

        /// <summary>
        /// Concatenates all the bytes of the TCP client
        /// </summary>
        /// <param name="client">tcp client</param>
        private void HandleClientComm(object client)
        {
            try
            {
                int i;
                Byte[] bytes = new Byte[524288];
                Byte[] buffer = null;
                Byte[] bytes_data = null;

                TcpClient tcpClient = (TcpClient)client;
                NetworkStream stream = tcpClient.GetStream();

                while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
                {
                    if (buffer != null)
                    {
                        bytes_data = new Byte[buffer.Length + i];
                        buffer.CopyTo(bytes_data, 0);
                        for (int j = 0; j < i; j++)
                            bytes_data[j + buffer.Length] = bytes[j];
                    }
                    else
                    {
                        bytes_data = new Byte[i];
                        for (int j = 0; j < i; j++)
                            bytes_data[j] = bytes[j];
                    }

                    buffer = bytes_data;
                }

                //tcpClient.Client.RemoteEndPoint.ToString();
                String client_ip = ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address.ToString();
                //String client_port = ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Port.ToString();          

                //Console.WriteLine(System.Text.Encoding.ASCII.GetString(bytes_data));
                ParseTCPMessages(bytes_data, client_ip);

                tcpClient.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine("Handle client conn exception: " + e.Message);

            }
        }

        /// <summary>
        /// Parse the information in a stream of bytes
        /// </summary>
        /// <param name="data">stream of bytes to be parsed</param>
        private void ParseTCPMessages(Byte[] data, String ip)
        {
            try
            {
                Int32 data_table_id, data_type;
                String data_nickname, data_data;
               
                String data_string = System.Text.Encoding.ASCII.GetString(data);

                int val1 = data_string.IndexOf(":");
                data_string = data_string.Substring(val1 + 1);

                val1 = data_string.IndexOf(":");

                String table_id = data_string.Substring(0, val1);

                try
                {
                    data_table_id = Convert.ToInt32(table_id);
                }
                catch (Exception)
                {
                    return;
                }

                data_string = data_string.Substring(val1 + 1);
                val1 = data_string.IndexOf(":");

                String type = data_string.Substring(0, val1);
                try
                {
                    data_type = Convert.ToInt32(type);
                }
                catch (Exception)
                {
                    return;
                }

                data_string = data_string.Substring(val1 + 1);
                val1 = data_string.IndexOf(":");

                data_nickname = data_string.Substring(0, val1);
                data_string = data_string.Substring(val1 + 1);
                val1 = data_string.IndexOf(":");

                data_data = data_string.Substring(0, val1);
                //Console.WriteLine(data_type + " --- " + data_data + " --- "+ data_nickname+ " --- "+data_table_id);
                
                switch (data_type)
                {
                    case NetMessages.MESSAGE_DISCOVER:
                        Received_Discover(data_nickname, ip,data_data);
                        break;
                    case NetMessages.MESSAGE_CREATE_TABLE:
                        Received_Create_Table(data_nickname, data_data);
                        break;
                    case NetMessages.MESSAGE_JOIN_TABLE:
                        Received_Join_Table(data_table_id, data_nickname, data_data);
                        break;
                    case NetMessages.MESSAGE_START_GAME:
                        Received_Start_Game(data_table_id, data_nickname, data_data);
                        break;
                    case NetMessages.MESSAGE_CANCEL_GAME:
                        Received_Cancel_Game(data_table_id, data_nickname, data_data);
                        break;
                    case NetMessages.MESSAGE_CHANGE_CARDS:
                        Received_Change_Cards(data_table_id, data_nickname, data_data);
                        break;
                    case NetMessages.MESSAGE_DRAW_CARD:
                        Received_Draw_Cards(data_table_id, data_nickname, data_data);
                        break;
                    case NetMessages.MESSAGE_PUT_CARD:
                        Received_Put_Card(data_table_id, data_nickname, data_data);
                        break;
                    case NetMessages.MESSAGE_CONTINUE:
                        Received_Continue(data_table_id, data_nickname, data_data);
                        break;
                    case NetMessages.MESSAGE_SCORE:
                        Received_Score(data_table_id, data_nickname, data_data);
                        break;
                    case NetMessages.MESSAGE_SCORE_HELP:
                        Received_Score_Help(data_table_id, data_nickname, data_data);
                        break;
                    case NetMessages.MESSAGE_DISCARD_CARDS:
                        Received_Discard_Cards(data_table_id, data_nickname, data_data);
                        break;
                    case NetMessages.MESSAGE_DISCARD_PUBLIC_CARDS:                        
                        Received_Discard_Public_Cards(data_table_id, data_nickname,data_data);
                        break;
                    case NetMessages.MESSAGE_PUT_HOUSES:
                        Received_Put_Houses(data_table_id, data_nickname, data_data);
                        break;
                    case NetMessages.MESSAGE_QUIT:
                        Received_Quit(data_table_id, data_nickname, data_data);
                        break;
                }
           }
           catch (Exception)
           {
               data = null;
           }
        }
        
        /// <summary>
        /// Send to a client, the player list connected
        /// </summary>
        /// <param name="player">Player </param>
        /// <param name="listPlayers">List of players</param>
        public void Send_Players(Player player, ArrayList listPlayers)
        {
            Player p;
            try
            {
                TcpClient client = new TcpClient(player.Ip,player.Port);
                String message = ":" + NetMessages.MESSAGE_PLAYERS + "::";
                for (int i = 0; i < listPlayers.Count; i++)
                {
                    p = (Player)listPlayers[i];
                    message = message + p.NickName + "+";
                }
                message = message + ":";

                Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
                NetworkStream stream = client.GetStream();

                stream.Write(data, 0, data.Length);

                stream.Close();
                client.Close();

            }
            catch(Exception e)
            {
                Console.WriteLine("MESSAGE_PLAYERS exception: " + e.Message);
                OnClientSocketError(player, player.NickName);
            }
        }
         
        /// <summary>
        /// Sends to a client, list of rooms and players that are in the rooms
        /// </summary>
        /// <param name="player">Player who made discover</param>
        /// <param name="listTables">Arraylist with tables list</param>
        public void Send_Offer(Player player, ArrayList listTables)
        {
            Room r;
            Player pr;
            try
            {
               TcpClient client = new TcpClient(player.Ip,player.Port);
                //OFFER null ListOfTables
               String message = ":" + NetMessages.MESSAGE_OFFER + "::";
               
                // id1|name1||nick1+nick2+|++id2...
                for (int i = 0; i < listTables.Count; i++)
                {
                    r = (Room)(listTables[i]);
                    message = message + r.ID + "+" + r.IsGameStarted + "|" + r.Name + "||";
                    
                    for (int j = 0; j < 4; j++)
                    {
                        pr = r.ListPlayer[j];
                        if (pr != null)
                            message = message + pr.NickName + "+";
                        else message = message + "null" + "+";
                    }
                    message = message + "|" + "++";
                 }

                message = message + ":";

                Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
                NetworkStream stream = client.GetStream();

                stream.Write(data, 0, data.Length);

                stream.Close();
                client.Close();
            }
            catch (Exception e)
            {
                //TODO
                Console.WriteLine("Offer exception: " + e.Message);
                OnClientSocketError(player, player.NickName);
            }
        }

        /// <summary>
        /// Sends deny to a specific user which doesn't meet certain conditions
        /// </summary>
        /// <param name="ip">user's ip address</param>
        /// <param name="port">user's port</param>
        public void Send_NACK_Offer(String ip, Int32 port)
        {
            try
            {
                TcpClient client = new TcpClient(ip, port);
                //NACK_OFFER null null 
                String message = ":" + NetMessages.MESSAGE_NACK_OFFER + ":::";
                
                Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
                NetworkStream stream = client.GetStream();

                stream.Write(data, 0, data.Length);

                stream.Close();
                client.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine("Nack Offer exception: "+ e.Message);
                Send_NACK_Offer(ip, port);
            }
        }

        /// <summary>
        /// Sends accept to a player who made request to join on a certain table
        /// </summary>
        /// <param name="player">Player</param>
        public void Send_ACK_JoinTable(Player player, Int32 table_id, ArrayList listRooms)
        {
            Room r;
            Player p;
            try
            {
                TcpClient client = new TcpClient(player.Ip, player.Port);
                //ACK_JOIN_TABLE null null
                String message = ":" + NetMessages.MESSAGE_ACK_JOIN_TABLE + ":" + table_id + ":|";
                
                for (int i = 0; i < listRooms.Count; i++){
                    r = (Room)listRooms[i];
                    if (r.ID.Equals(table_id))
                        for (int j = 0; j < 4; j++)
                        {
                            p = r.ListPlayer[j];
                            if (p != null)
                                message = message + p.NickName + "+" + p.IsReady + "+";
                            else 
                                message = message + "null" + "+" + "null" + "+";
                        }
                    }
                message = message + "|:";
                
                Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
                NetworkStream stream = client.GetStream();

                stream.Write(data, 0, data.Length);

                stream.Close();
                client.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine("ACkJoinTable exception: "+e.Message);
                OnClientSocketError(player, player.NickName);
            }
        }
        
        /// <summary>
        /// Sends accept if a table is valid and can be created
        /// </summary>
        /// <param name="player">Player</param>
        public void Send_ACK_CreateTable(Player player, Int32 table_id)
        {
            try
            {
                TcpClient client = new TcpClient(player.Ip, player.Port);
                //ACK_CREATE_TABLE null null
                String message = ":" + NetMessages.MESSAGE_ACK_CREATE_TABLE + "::" + table_id + ":";

                Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
                NetworkStream stream = client.GetStream();

                stream.Write(data, 0, data.Length);

                stream.Close();
                client.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine("AckCreateTable exception: " + e.Message);
                OnClientSocketError(player, player.NickName);
            }
        }

        /// <summary>
        /// Sends deny if a table isn't valid. 
        /// </summary>
        /// <param name="player">Player</param>
        public void Send_NACK_CreateTable(Player player)
        {
            try
            {
                TcpClient client = new TcpClient(player.Ip, player.Port);
                //NACK_CREATE_TABLE null null
                String message = ":" + NetMessages.MESSAGE_NACK_CREATE_TABLE + ":::";

                Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
                NetworkStream stream = client.GetStream();

                stream.Write(data, 0, data.Length);

                stream.Close();
                client.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine("NackCreateTable exception: " + e.Message);
                OnClientSocketError(player, player.NickName);
            }
        }

        /// <summary>
        /// Sends deny to a player who made request to join table
        /// </summary>
        /// <param name="player">Player</param>
        public void Send_NACK_Join_Table(Player player)
        {
            try
            {
                TcpClient client = new TcpClient(player.Ip, player.Port);
                //NACK_JOIN_TABLE null null
                String message = ":" + NetMessages.MESSAGE_NACK_JOIN_TABLE + ":::";
                
                Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
                NetworkStream stream = client.GetStream();

                stream.Write(data, 0, data.Length);

                stream.Close();
                client.Close();
            }
            catch (Exception e )
            {
                Console.WriteLine("NackJoinTable exception: " + e.Message);
                OnClientSocketError(player, player.NickName);
            }
        }

        /// <summary>
        /// Sends an announce that a player has join table
        /// </summary>
        /// <param name="player">Player that need to be announced</param>
        /// <param name="nickname">the nickname of the player who has joined</param>
        /// <param name="poz">the position of the new player in the table</param>
        public void Send_User_Join_Table(Player player, String nickname, Int32 poz)
        {
            try
            {
                //USER_JOIN_TABLE Nickname pozitie
                String message = ":" + NetMessages.MESSAGE_USER_JOIN_TABLE + ":" + nickname + ":" + poz + ":";
                TcpClient client = new TcpClient(player.Ip, player.Port);
             
                Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
                NetworkStream stream = client.GetStream();

                stream.Write(data, 0, data.Length);

                stream.Close();
                client.Close();
               
            }
            catch (Exception e)
            {
                Console.WriteLine("SendUserJoin exception: "+e.Message);
                OnClientSocketError(player, player.NickName);
            }
        }

        /// <summary>
        /// Sends that a user is ready
        /// </summary>
        /// <param name="player">Player that need to be announced</param>
        /// <param name="nickname">the nickname of the player who is ready</param>
        public void Send_User_Start(Player player, String nickname)
        {
            try
            {
                TcpClient client = new TcpClient(player.Ip, player.Port);
                //USER_START nickname null
                String message = ":" + NetMessages.MESSAGE_USER_START + ":" + nickname + "::";
                
                Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
                NetworkStream stream = client.GetStream();

                stream.Write(data, 0, data.Length);

                stream.Close();
                client.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine("SendUserStart exception: " +e.Message);
                OnClientSocketError(player, player.NickName);
            }
        }

        /// <summary>
        /// Sends that a user has cancel the "ready" state
        /// </summary>
        /// <param name="player">Player that need to be announced</param>
        /// <param name="nickname"></param>
        public void Send_User_Cancel(Player player, String nickname)
        {
            try
            {
                TcpClient client = new TcpClient(player.Ip, player.Port);
                //USER_CANCEL nickname null
                String message = ":" + NetMessages.MESSAGE_USER_CANCEL + ":" + nickname + "::";
                
                Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
                NetworkStream stream = client.GetStream();

                stream.Write(data, 0, data.Length);

                stream.Close();
                client.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine("SendUserCancel exception: "+e.Message);
                OnClientSocketError(player, player.NickName);
            }
        }

        /// <summary>
        /// Sends to a player that the game had been started and give him the first six cards
        /// </summary>
        /// <param name="player">Player</param>
        /// <param name="listSixCards">the list of the six cards</param>
        public void Send_Game_Start(Player player, ArrayList listSixCards )
        {
            CityCard c;
            try
            {
                TcpClient client = new TcpClient(player.Ip, player.Port);
                //GAME_START null 6cards
                String message = ":" + NetMessages.MESSAGE_GAME_START + "::";
                for (int i = 0; i < listSixCards.Count; i++)
                {
                    c = (CityCard)(listSixCards[i]);
                    message = message + c.CityName + "|";
                }
                message = message + ":";
                Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
                NetworkStream stream = client.GetStream();

                stream.Write(data, 0, data.Length);

                stream.Close();
                client.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine("SendGameStart exception: " + e.Message);
                OnClientSocketError(player, player.NickName);
            }
        }

        /// <summary>
        /// Sends an announce that tell user who turn is it
        /// </summary>
        /// <param name="player">Player that need to be announced</param>
        /// <param name="nickname">the nickname of the player who turn is it</param>
        public void Send_User_Turn(Player player, String nickname)
        {
            try
            {
                TcpClient client = new TcpClient(player.Ip, player.Port);
                //USER_TURN nickname null
                String message = ":" + NetMessages.MESSAGE_USER_TURN + ":" + nickname + "::";
                
                Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
                NetworkStream stream = client.GetStream();

                stream.Write(data, 0, data.Length);

                stream.Close();
                client.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine("SendUserTurn exception: " + e.Message);
                OnClientSocketError(player, player.NickName);
            }
        }

        /// <summary>
        /// Sends the next six cards
        /// </summary>
        /// <param name="player">Player</param>
        /// <param name="nickname">the nickname of the player who made the request</param>
        /// <param name="data_message">arralist with the name of the six cards</param>
        public void Send_Change_Cards(Player player, String nickname, String data_message )
        {
            try
            {
                TcpClient client = new TcpClient(player.Ip, player.Port);
                String message = ":" + NetMessages.MESSAGE_CHANGE_CARDS + ":" + nickname + ":" + data_message + ":";
                
                Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
                NetworkStream stream = client.GetStream();

                stream.Write(data, 0, data.Length);

                stream.Close();
                client.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine("SendChangeCards exception: " + e.Message);
                OnClientSocketError(player, player.NickName);
            }
        }

        /// <summary>
        /// Sends an announce that a player has draw a card from the six cards
        /// </summary>
        /// <param name="player">Player that need to be announced</param>
        /// <param name="nickname">the nickname of the player who draw the card</param>
        /// <param name="data_message">contains the position of the card from the arraylist and card name</param>        
        public void Send_Draw_Card(Player player, String nickname, String data_message )
        {
            try
            {
                TcpClient client = new TcpClient(player.Ip, player.Port);               
                //DRAW_CARD nickname pozitie,nume
                String message = ":" + NetMessages.MESSAGE_DRAW_CARD + ":" + nickname + ":" + data_message + ":";

                Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
                NetworkStream stream = client.GetStream();

                stream.Write(data, 0, data.Length);

                stream.Close();
                client.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine("SendDrawCard exception: " + e.Message);
                OnClientSocketError(player, player.NickName);
            }
        }

        /// <summary>
        /// Sends an announce that a player has put down a card
        /// </summary>
        /// <param name="player">Player that need to be announced</param>
        /// <param name="nickname">the nickname of the player who put down a card</param>
        /// <param name="cityName">the name of the card</param>
        public void Send_Put_Card(Player player,String nickname, String cityName)
        {
            try
            {
                TcpClient client = new TcpClient(player.Ip, player.Port);
                //PUT_CARD nickname carte
                String message = ":" + NetMessages.MESSAGE_PUT_CARD + ":" + nickname + ":" + cityName + ":";

                Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
                NetworkStream stream = client.GetStream();

                stream.Write(data, 0, data.Length);

                stream.Close();
                client.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine("SendPutCard exception: "+ e.Message);
                OnClientSocketError(player, player.NickName);
            }
        }

        /// <summary>
        /// Sends an announce that a player wants to score on his hand
        /// </summary>
        /// <param name="player">Player who need to be announced</param>
        /// <param name="nickname">the nickname of the player who scored</param>
        public void Send_Score(Player player, String nickname)
        {
            try
            {
                TcpClient client = new TcpClient(player.Ip, player.Port);
                //SCORE nickname null
                String message = ":" + NetMessages.MESSAGE_SCORE + ":" + nickname + "::";

                Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
                NetworkStream stream = client.GetStream();

                stream.Write(data, 0, data.Length);

                stream.Close();
                client.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine("SendScore exception: " +e.Message);
                OnClientSocketError(player, player.NickName);
            }
        }
        
        /// <summary>
        /// Sends an announce that a player had score with help
        /// </summary>
        /// <param name="player">Player that need to be announced</param>
        /// <param name="nickname">the nickname of the player who scored</param>
        public void Send_Score_Help(Player player, String nickname)
        {
            try
            {
                TcpClient client = new TcpClient(player.Ip, player.Port);
                //SCORE_HELP nickname null
                String message = ":" + NetMessages.MESSAGE_SCORE_HELP + ":" + nickname + "::";

                Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
                NetworkStream stream = client.GetStream();

                stream.Write(data, 0, data.Length);

                stream.Close();
                client.Close();
            }
            catch (Exception e) 
            {
                Console.WriteLine("SendSCoreHelp exception: "+e.Message);
                OnClientSocketError(player, player.NickName);
            }
        }

        /// <summary>
        /// Sends an announce that a player requested to discard cards the six cards
        /// </summary>
        /// <param name="player">Player that need to be announced</param>
        /// <param name="nickname">the nickname of the player who made the request</param>
        /// <param name="data_message">arralist with the name of the new six cards</param>
        public void Send_Discard_Card(Player player, String nickname, String data_message)
        {
            try
            {
                TcpClient client = new TcpClient(player.Ip, player.Port);
                //DISCARD_CARD nickname lista_carti
                String message = ":" + NetMessages.MESSAGE_DISCARD_CARDS + ":" + nickname + ":" + data_message + ":";
                
                Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
                NetworkStream stream = client.GetStream();

                stream.Write(data, 0, data.Length);

                stream.Close();
                client.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine("SendDiscardCard exception: " + e.Message);
                OnClientSocketError(player, player.NickName);
            }
 
        }


        /// <summary>
        /// Annonce players that the player which turn is has discard his public cards
        /// </summary>
        /// <param name="player">Player that need to be announced</param>
        /// <param name="nickname">Nickname of the player who made the move</param>
        public void Send_Discard_Public_Cards(Player player, String nickname)
        {
            try
            {
                TcpClient client = new TcpClient(player.Ip, player.Port);
                //DISCARD_PUBLIC_CARD nickname lista_carti
                String message = ":" + NetMessages.MESSAGE_DISCARD_PUBLIC_CARDS + ":" + nickname + "::";

                Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
                NetworkStream stream = client.GetStream();

                stream.Write(data, 0, data.Length);

                stream.Close();
                client.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine("SendDiscardPublicCard exception: " + e.Message);
                OnClientSocketError(player, player.NickName);
            }

        }

        /// <summary>
        /// Sends an announce that a player has put houses on the game map
        /// </summary>
        /// <param name="player">Player that need to be announced</param>
        /// <param name="nickname">the nickname of the player who put houses on the map</param>
        /// <param name="data_message">arraylist with the names of the cities</param>
        public void Send_Put_Houses(Player player, String nickname, String data_message)
        {
            try
            {
                TcpClient client = new TcpClient(player.Ip, player.Port);
                //PUT_HOUSES nickname lista_orase
                String message = ":" + NetMessages.MESSAGE_PUT_HOUSES + ":" + nickname + ":" + data_message + ":";

                Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
                NetworkStream stream = client.GetStream();

                stream.Write(data, 0, data.Length);

                stream.Close();
                client.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine("SendPutHouses exception: " +e.Message);
                OnClientSocketError(player, player.NickName);
            }
        }

        /// <summary>
        /// Sends an announce that a player has quit the game
        /// </summary>
        /// <param name="player">Player who need to be announced</param>
        /// <param name="nickname">the nickname of the player who had quit</param>
        public void Send_Quit(Player player,String nickname)
        {
            try
            {
                TcpClient client = new TcpClient(player.Ip, player.Port);
                //QUIT nickname null
                String message = ":" + NetMessages.MESSAGE_QUIT + ":" + nickname + "::";

                Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
                NetworkStream stream = client.GetStream();

                stream.Write(data, 0, data.Length);

                stream.Close();
                client.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine("SendQuit exception: " + e.Message);
                OnClientSocketError(player, player.NickName);
            }
        }

        /// <summary>
        /// Send disconnect message
        /// </summary>
        /// <param name="player">Player</param>
        public void Send_Disconnect(Player player)
        {
            try
            {
                TcpClient client = new TcpClient(player.Ip, player.Port);

                String message = ":" + NetMessages.MESSAGE_DISCONNECT + ":::";

                Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
                NetworkStream stream = client.GetStream();

                stream.Write(data, 0, data.Length);

                stream.Close();
                client.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine("SendDisconnect exception: " + e.Message);
                OnClientSocketError(player, player.NickName);
            }
        }

        /// <summary>
        /// Server has received discover message and test if is valid.
        /// </summary>
        /// <param name="nickname">Nickname of the client </param>
        /// <param name="ip">Ip address of the client</param>
        /// <param name="port">Port of the client</param>
        public void Received_Discover(String nickname,String ip, String port)
        {
            _serverCore.AddClient(nickname, ip, port);  
        }

        /// <summary>
        /// Server has received create table message from a client and we process it
        /// </summary>
        /// <param name="nickname">Nickname</param>
        /// <param name="data">The name of the room</param>
        public void Received_Create_Table(String nickname, String data)
        {
            //In data o sa-mi vina numele room-ului
            _serverCore.CreateRoom(data, nickname);
        }

        /// <summary>
        /// Server has received a join request from a client and we process it
        /// </summary>
        /// <param name="table_id">Table id where he want to join</param>
        /// <param name="nickname">Nickname of the client</param>
        /// <param name="data">Some data. here is ignored</param>
        public void Received_Join_Table(Int32 table_id, String nickname, String data)
        {
            _serverCore.UserJoinTable(table_id, nickname);
        }

        /// <summary>
        /// Server received start game message from a client in a room, means that he's ready
        /// </summary>
        /// <param name="table_id">Table id</param>
        /// <param name="nickname">Nickname of the player</param>
        /// <param name="data">Some data. here is ignored</param>
        public void Received_Start_Game(Int32 table_id, String nickname, String data)
        {
            _serverCore.SetUserReady(table_id, nickname);
        }

        /// <summary>
        /// Server received cancel game message, means that he isn't ready
        /// </summary>
        /// <param name="table_id">Table id</param>
        /// <param name="nickname">Nickname of the player</param>
        /// <param name="data">Some data. here is ignored</param>
        public void Received_Cancel_Game(Int32 table_id, String nickname, String data)
        {
            _serverCore.CancelUserReady(table_id, nickname);
        }

        /// <summary>
        /// Server received change cards from a player
        /// </summary>
        /// <param name="table_id">Table id</param>
        /// <param name="nickname">Nickname</param>
        /// <param name="data">The next 6 cards</param>
        public void Received_Change_Cards(Int32 table_id, String nickname, String data)
        {
            _serverCore.DoMove(NetMessages.MESSAGE_CHANGE_CARDS, table_id, nickname, data);
        }

        /// <summary>
        /// Server received a draw card message from a player
        /// </summary>
        /// <param name="table_id">Table id</param>
        /// <param name="nickname">Nickname</param>
        /// <param name="data">Card draw</param>
        public void Received_Draw_Cards(Int32 table_id, String nickname, String data)
        {
            _serverCore.DoMove(NetMessages.MESSAGE_DRAW_CARD, table_id, nickname, data);
        }

        /// <summary>
        /// Server received put card message from a player
        /// </summary>
        /// <param name="table_id">Table id</param>
        /// <param name="nickname">Nickname</param>
        /// <param name="data">Card that is put down</param>
        public void Received_Put_Card(Int32 table_id, String nickname, String data)
        {
            _serverCore.DoMove(NetMessages.MESSAGE_PUT_CARD, table_id, nickname, data);
        }

        /// <summary>
        /// Server received continue message from a player
        /// </summary>
        /// <param name="table_id">Table id</param>
        /// <param name="nickname">Nickname</param>
        /// <param name="data">Some data that are ignored :)</param>
        public void Received_Continue(Int32 table_id, String nickname, String data)
        {
            _serverCore.DoTurnMove(NetMessages.MESSAGE_CONTINUE, table_id, nickname);
        }

        /// <summary>
        /// Server received score message from a player
        /// </summary>
        /// <param name="table_id">Table id</param>
        /// <param name="nickname">Nickname</param>
        /// <param name="data">Some data that are ignored. if exists</param>
        public void Received_Score(Int32 table_id, String nickname, String data)
        {
            _serverCore.DoTurnMove(NetMessages.MESSAGE_SCORE, table_id, nickname);
        }

        /// <summary>
        /// Server received score help message from a player
        /// </summary>
        /// <param name="table_id">Table id</param>
        /// <param name="nickname">Nickname</param>
        /// <param name="data">Some data that are ignored</param>
        public void Received_Score_Help(Int32 table_id, String nickname, String data)
        {
            _serverCore.DoMove(NetMessages.MESSAGE_SCORE_HELP, table_id, nickname, data);
        }

        /// <summary>
        /// Server received discard cards message from a player
        /// </summary>
        /// <param name="table_id">Table id</param>
        /// <param name="nickname">Nickname</param>
        /// <param name="data">Cards that are discarded</param>
        public void Received_Discard_Cards(Int32 table_id, String nickname, String data)
        {
            _serverCore.DoMove(NetMessages.MESSAGE_DISCARD_CARDS, table_id, nickname, data);
        }

        /// <summary>
        /// Server received discard public cards message from a player
        /// </summary>
        /// <param name="table_id">Table id</param>
        /// <param name="nickname">Nickname</param>
        /// <param name="data">Cards that are discarded</param>
        public void Received_Discard_Public_Cards(Int32 table_id, String nickname, String data)
        {
            _serverCore.DoMove(NetMessages.MESSAGE_DISCARD_PUBLIC_CARDS, table_id, nickname, data);
        }

        /// <summary>
        /// Server received put houses message from a player
        /// </summary>
        /// <param name="table_id">Table id</param>
        /// <param name="nickname">Nickname</param>
        /// <param name="data">The cities where the player has put houses</param>
        public void Received_Put_Houses(Int32 table_id, String nickname, String data)
        {
            _serverCore.DoMove(NetMessages.MESSAGE_PUT_HOUSES, table_id, nickname, data);
        }

        /// <summary>
        /// Server received quit message from a player
        /// </summary>
        /// <param name="table_id">Table id</param>
        /// <param name="nickname">Nickname</param>
        /// <param name="data">some data that are ignored</param>
        public void Received_Quit(Int32 table_id, String nickname, String data)
        {
            _serverCore.DoDelete(table_id, nickname);
        }

        /// <summary>
        /// Function that is used to send disconnect message to all players connected
        /// </summary>
        public void DisconnectEvent()
        {
            OnDisconnect();
        }
    }
}
